from panda3d.core import Vec2, Point3, Vec3, Vec4, BitMask32
from direct.interval.IntervalGlobal import *
import math
from pandac.PandaModules import CollisionSphere, CollisionNode, CollisionHandlerPusher, CollisionTraverser, CollisionHandlerQueue, CollisionTube
from pandac.PandaModules import TextureStage

def distance(pos1, pos2):
	diff = pos1 - pos2
	return math.sqrt(diff[0]**2 + diff[1]**2 + diff[2]**2)
	
def length(pos):
	return math.sqrt(pos[0]**2 + pos[1]**2 + pos[2]**2)

def length2D(pos):
	return math.sqrt(pos[0]**2 + pos[1]**2)

'''
	Andrew Oberlin
	Date: March 6, 2012
'''
class VisualObject:
	'''
		This object will extended for buildings and other objects
		that are placed within the scene
		
		It represents the minerals in the game
	'''
	def __init__(self, parent, dummy, key):
		self.parent = parent
		self.dummy = dummy
		self.object = None
		self.model = None
		self.isPlatform = 0
		self.key = key
		self.loadModel(firstTime=True)
		
		self.collisionType = None
		self.collisionSolid = None
		self.collisionNode = None
		self.cnodePath = None
		
		
		
	'''
		Loads a model correctly
	'''
	def loadModel(self, firstTime=False):
		if (self.isPlatform == 1 or firstTime):
			if(self.model):
				self.model.removeNode()
			self.model = self.parent.loader.loadModelCopy("models/plane")
			self.model.reparentTo(self.dummy)
			self.isPlatform = 0
			self.model.setCollideMask(BitMask32(0x01))
			self.model.setTag('key', self.key)
		
	'''
		Loads a model correctly in 3D
	'''
	def load3DModel(self):
		if (self.isPlatform == 0):
			if(self.model):
				self.model.removeNode()
			self.model = self.parent.loader.loadModelCopy("models/cube")
			self.model.setColor(1, 1, 1, 1)
			self.model.reparentTo(self.dummy)
			self.model.setScale(0.25)
			self.isPlatform = 1
			self.model.setCollideMask(BitMask32(0x01))
			self.model.setTag('key', self.key)
		
	'''
		Sets the texture according to the current object
	'''
	def setTexture(self):
		if (self.object):
			texture = self.parent.loader.loadTexture(self.object.getMainTexture())
			self.model.setTexture(texture)
			self.model.setTransparency(1)
			
	'''
		Set's this object to be a visual wrapper
		for the object specified
	'''
	def setObjectType(self, obj):
		self.object = obj
		
		if (self.object.getIsPlatform()):
			self.load3DModel()
			self.setTexture()
		else:
			self.loadModel()
			self.setTexture()
		
	'''
		Adds a collision Sphere
		params = (center_x, center_y, center_z, radius)
	'''
	def addCollisionSphere(self, params=(0, 0, 0, 0.75)):
		if (self.cnodePath):
			self.cnodePath.removeNode()
		self.collisionSolid = CollisionSphere(params[0], params[1], params[2], params[3])
		self.collisionNode = CollisionNode('cnode_' + self.key)
		self.cnodePath = self.model.attachNewNode(self.collisionNode)
		self.cnodePath.node().addSolid(self.collisionSolid)
		self.cnodePath.show()
		self.collisionNode.setIntoCollideMask(BitMask32(0x02))
		self.collisionType = "sphere"
		
	'''
		Adds a collision Cylinder
		params = (ax, ay, az, bx, by, bz, radius)
	'''
	def addCollisionCyl(self, params=(0, 0, -1, 0, 0, 1, 0.25)):
		if (self.cnodePath):
			self.cnodePath.removeNode()
		self.collisionSolid = CollisionTube(params[0], params[1], params[2], params[3], params[4], params[5], params[6])
		self.collisionNode = CollisionNode('cnode_' + self.key)
		self.cnodePath = self.model.attachNewNode(self.collisionNode)
		self.cnodePath.node().addSolid(self.collisionSolid)
		self.cnodePath.show()
		self.collisionNode.setIntoCollideMask(BitMask32(0x02))
		self.collisionType = "cyl"
			
	'''
		Increases the scale of the collision solid
	'''
	def increaseCollisionScale(self, direction):
		if (self.collisionType):
			if (self.collisionType == "sphere"):
				self.collisionSolid.setRadius(self.collisionSolid.getRadius() + 0.1)
				#self.addColllisionSphere(params=(0,0,0,))				
			elif (self.collisionType == "cyl"):
				if (direction == 'x'):
					self.collisionSolid.setRadius(self.collisionSolid.getRadius() + 0.1)
				else:
					a = Point3(self.collisionSolid.getPointA())
					b = Point3(self.collisionSolid.getPointB())
					a.setZ(a.getZ() - 0.05)
					b.setZ(b.getZ() + 0.05)
					self.collisionSolid.setPointA(a)
					self.collisionSolid.setPointB(b)
	
	'''
		Decreases the scale of the collision solid
	'''
	def decreaseCollisionScale(self, direction):
		if (self.collisionType):
			if (self.collisionType == "sphere"):
				self.collisionSolid.setRadius(self.collisionSolid.getRadius() - 0.1)
			elif (self.collisionType == "cyl"):
				if (direction == 'x'):
					self.collisionSolid.setRadius(self.collisionSolid.getRadius() - 0.1)
				else:
					a = Point3(self.collisionSolid.getPointA())
					b = Point3(self.collisionSolid.getPointB())
					if (b.getZ() - 0.05 > a.getZ() + 0.05):
						a.setZ(a.getZ() + 0.05)
						b.setZ(b.getZ() - 0.05)
					self.collisionSolid.setPointA(a)
					self.collisionSolid.setPointB(b)
	
	def hideCNodePath(self):
		self.cnodePath.hide()
	'''
		Hides this model from site
	'''
	def hide(self):
		self.model.hide()
		
	'''
		Makes the object visible
	'''
	def show(self):
		self.model.show()
	
	'''
		Wrapper for the model's position method
	'''
	def setPos(self, pos):
		self.model.setPos(pos)
		
	'''
		Wrapper for the model's position method
	'''
	def setX(self, x):
		self.model.setX(x)
		
	'''
		Wrapper for the model's position method
	'''
	def setY(self, y):
		self.model.setY(y)
		
	'''
		Wrapper for the model's position method
	'''
	def setZ(self, z):
		self.model.setZ(z)
		
		
	'''
		Wrapper for the model's position method
	'''
	def getPos(self):
		return self.model.getPos()
		
	'''
		Wrapper for the model's position method
	'''
	def getX(self):
		return self.model.getX()
		
	'''
		Wrapper for the model's position method
	'''
	def getY(self):
		return self.model.getY()
		
		
	'''
		Wrapper for the model's position method
	'''
	def getZ(self):
		return self.model.getZ()
	
	'''
		Wrapper for the model's position method
	'''
	def setHpr(self, hpr):
		self.model.setHpr(hpr)
		
	'''
		Wrapper for the model's position method
	'''
	def setH(self, h):
		self.model.setH(h)
		
	'''
		Wrapper for the model's position method
	'''
	def setP(self, p):
		self.model.setP(p)
		
	'''
		Wrapper for the model's position method
	'''
	def setR(self, r):
		self.model.setR(r)
		
		
	'''
		Wrapper for the model's hpr method
	'''
	def getHpr(self):
		return self.model.getHpr()
		
	'''
		Wrapper for the model's heading method
	'''
	def getH(self):
		return self.model.getH()
		
	'''
		Wrapper for the model's pitch method
	'''
	def getP(self):
		return self.model.getP()
		
	'''
		Wrapper for the model's roll method
	'''
	def getR(self):
		return self.model.getR()	
		
	'''
		Removes the model node
	'''
	def removeNode(self):
		self.model.removeNode()
		
		
	'''
		Gets the texture for the model node
	'''
	def getTexture(self):
		if (self.object):
			return self.object.getMainTexture()
		else:
			return ""
	
	'''
	
	'''
	def setScale(self, scale):
		self.model.setScale(scale)
		
	'''
	
	'''
	def getScale(self):
		return self.model.getScale()
	
	'''
	
	'''
	def setColor(self, r, g, b, a):
		self.model.setColorScale(r, g, b, a)
	
	'''
		Sets the key of the collision node and this
		object in general
	'''
	def setKey(self, key):
		self.key = key
		self.model.setTag('key', key)
		
	'''
	
	'''
	def getKey(self):
		return self.key
		
	def setModelTexture(self, texture):
		self.model.setTexture(texture)
		
		
	def __str__(self):
		return str(self.object) + ", key: " + self.key 
		
		
class VisualObjectSave:
	'''
	### Name: __init__ (Constructor)
	### Author: Andrew Oberlin, Patrick Delaney
	### Parameters: None
	### Description: 
	'''
	def __init__(self, visual_obj):
		self.object = visual_obj.object
		self.pos = visual_obj.getPos()
		self.hpr = visual_obj.getHpr()
		self.key = visual_obj.key
		self.scale = visual_obj.getScale()
		self.collisionType = visual_obj.collisionType
		self.pointA = None
		self.pointB = None
		self.radius = 0
		self.center = None
		if (self.collisionType):
			if (self.collisionType == "cyl"):
				self.radius = visual_obj.collisionSolid.getRadius()
				self.pointA = visual_obj.collisionSolid.getPointA()
				self.pointB = visual_obj.collisionSolid.getPointB()
			else:
				self.radius = visual_obj.collisionSolid.getRadius()
				self.center = visual_obj.collisionSolid.getCenter()
	'''
		Exports this object as a visual object
		with the given dummy node
	'''
	def exportToVisualObject(self, parent, dummy):
		vObj = VisualObject(parent, dummy, self.key)
		vObj.setObjectType(self.object)
		vObj.setPos(self.pos)
		vObj.setHpr(self.hpr)
		vObj.setScale(self.scale)
		if (self.collisionType):
			if (self.collisionType == "cyl"):
				vObj.addCollisionCyl(
					params=(
						self.pointA[0], self.pointA[1], self.pointA[2], 
						self.pointB[0], self.pointB[1], self.pointB[2], self.radius
					)
				)
			else:
				vObj.addCollisionSphere(
					params=(
						self.center[0], self.center[1], self.center[2], self.radius
					)
				)
		return vObj
		